package ws

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/nntaoli-project/goex"
	"github.com/nntaoli-project/goex/binance"
	"net/http"
	"net/url"
	"quantization_trading/src/models"
	"quantization_trading/src/util"
	"time"
)

type SubscribeOrderStruct struct {
	Exchange string
	ContractType string

	//order
	Order chan models.Order

	ApiKey     string
	SecretKey  string
	Passphrase string
}

func NewSubOrder(Exchange, ContractType, ApiKey,SecretKey,Passphrase string) SubscribeOrderStruct {
	sub :=SubscribeOrderStruct{
		Exchange: Exchange,
		ContractType: ContractType,
		ApiKey: ApiKey,
		SecretKey: SecretKey,
		Passphrase: Passphrase,
	}
	sub.Order = make(chan models.Order, 10)
	return sub
}

func (s *SubscribeOrderStruct) APIKey(key string) *SubscribeOrderStruct {
	s.ApiKey = key
	return s
}
func (s *SubscribeOrderStruct) ApiPassphrase(key string) *SubscribeOrderStruct {
	s.Passphrase = key
	return s
}
func (s *SubscribeOrderStruct) SetPassphrase(key string) *SubscribeOrderStruct  {
	s.Passphrase = key
	return s
}

func (s *SubscribeOrderStruct) SubscribeOrder()  error{
	switch s.Exchange {
		case "binance":
			go s.subscribeOrderBinance()
			return nil
		default:
			fmt.Println("暂时没该交易所")
			return errors.New("暂时没该交易所")
	}
}








// 这些方法不应该在这，只不过是底层还没实现该方法
func (s *SubscribeOrderStruct) subscribeOrderBinance()  {
	switch s.ContractType {
	case goex.SWAP_USDT_CONTRACT:
		goex.NewWsBuilder().ProtoHandleFunc(s.handle).AutoReconnect().WsUrl(fmt.Sprintf("%s/%s",binance.TESTNET_FUTURE_USD_WS_BASE_URL, s.getListenKey())).Build()
	default:
		goex.NewWsBuilder().ProtoHandleFunc(s.handle).AutoReconnect().WsUrl(fmt.Sprintf("%s/%s",binance.TESTNET_FUTURE_COIN_WS_BASE_URL, s.getListenKey()) ).Build()
	}

	t := time.NewTicker(time.Second * 60 * 50)
	defer t.Stop()
	for  {
		select {
		case <-t.C:
			s.getListenKey()
		}
	}
}

func (s *SubscribeOrderStruct) getListenKey() string {
	client := http.DefaultClient
	param := url.Values{}
	var reqUrl string
	switch s.ContractType {
	case goex.SWAP_USDT_CONTRACT:
		reqUrl = "https://fapi.binance.com/fapi/v1/listenKey"
	default:
		reqUrl = "https://dapi.binance.com/dapi/v1/listenKey"
	}
	resp, err := goex.HttpPostForm2(client,reqUrl,param,map[string]string{"X-MBX-APIKEY": s.ApiKey})
	respmap := make(map[string]interface{})
	err = json.Unmarshal(resp, &respmap)
	if err != nil {
		return ""
	}
	return respmap["listenKey"].(string)
}


func (s *SubscribeOrderStruct) handle(data []byte) error {
	var m = make(map[string]interface{}, 4)
	err := json.Unmarshal(data, &m)
	if err != nil {
		return err
	}
	if e,ok := m["e"].(string); ok && e == "ORDER_TRADE_UPDATE" {
		o := m["o"].(map[string]interface{})
		order := models.Order{
			Cid: o["c"].(string),
			ExecutedQty: goex.ToFloat64(o["z"]),
			OrderId:fmt.Sprintf("%.0f",o["i"]),
			AvgPrice: goex.ToFloat64(o["ap"]),
			OrigQty: goex.ToFloat64(o["q"]),
			Price: goex.ToFloat64(o["p"]),
			OType: util.AdaptOType(o["S"].(string),o["ps"].(string)),
			Symbol: o["s"].(string),
			UpdateTime: goex.ToInt64(o["T"]),
		}
		switch o["o"] {
		case "LIMIT":
			order.Type = util.LIMIT
		case "MARKET":
			order.Type = util.MARKET
		case "STOP":
			order.Type =util.STOP
		case "STOP_MARKET":
			order.Type= util.STOP_MARKET
		}
		if order.ExecutedQty == 0 {
			order.Status = util.NOT_DONE
		}else if order.ExecutedQty == order.OrigQty {
			order.Status = util.OVER_DONE
		}else {
			order.Status = util.SOME_DONE
		}
		if (order.OType == 3 || order.OType == 4) && order.Status == util.OVER_DONE{
			order.StatusUse = false
		}else if o["X"].(string) == "CANCELED" || o["X"].(string) == "EXPIRED"{
			//撤单or订单失败
			order.StatusUse = false
		}else {
			order.StatusUse = true
		}
		s.Order <- order
	}
	return nil
}
